#include "cschprocessposition.h"
#include "cschdatacollector.h"
#include "csysparamdata.h"
#include "cjgorderprocess.h"
#include "cjgprocessschedule.h"

#include "cprescheduling.h"
#include "global.h"

CSchProcessPosition::CSchProcessPosition() {}

void CSchProcessPosition::CalculateScore()
{
    float fb = 0.0;
    fb = this->pSchData->hParamSet["SchPower_LastNBox"]->ValueFloat();
    CalculateItem_1(fb/100.0);

    fb = this->pSchData->hParamSet["SchPower_DeadLine"]->ValueFloat();
    CalculateItem_2(fb / 100.0);

    fb = this->pSchData->hParamSet["SchPower_Efficiency"]->ValueFloat();
    CalculateItem_3(fb / 100.0);

    fb = this->pSchData->hParamSet["SchPower_ProcessChange"]->ValueFloat();
    CalculateItem_4(fb / 100.0);

    fb = this->pSchData->hParamSet["SchPower_ProcessPrepare"]->ValueFloat();
    CalculateItem_5(fb / 100.0);

    fb = this->pSchData->hParamSet["SchPower_ProcessBoxful"]->ValueFloat();
    CalculateItem_6(fb / 100.0);

    CalculateItem_7(1.0);

    fb = this->pSchData->hParamSet["SchPower_PosFree"]->ValueFloat();
    CalculateItem_8(fb / 100.0);

    fb = 0.0;
    fb = this->pSchData->hParamSet["SchPower_AddPos"]->ValueFloat();
    CalculateItem_9(fb / 100.0);

    fb = 0.0;
    fb = this->pSchData->hParamSet["SchPower_MachineType"]->ValueFloat();
    CalculateItem_12(fb / 100.0);

    fb = 0.0;
    fb = this->pSchData->hParamSet["SchPower_DoneInOrder"]->ValueFloat();
    CalculateItem_13(fb / 100.0);

    fb = 0.0;
    fb = this->pSchData->hParamSet["SchPower_ProcessTypeRate"]->ValueFloat();
    CalculateItem_14(fb / 100.0);


    CalculateItem_10(1.0);

}

// void CSchProcessPosition::CalculateItem_1(float ratio)
// {
//     if (ratio < 0.01)return;
//     //int paramBoxCnt = this->pSchData->hParamSet["MinInLibBoxPer"]->ValueInt();
//     //int ParamSTDcnt = this->pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();
//     QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
//     for (iter = this->ProcessPosition.hProcessSet.begin();
//          iter != this->ProcessPosition.hProcessSet.end(); ++iter)
//     {
//         CJgOrderProcess * pOp = iter.value();
//         if (pOp->mScheduling->mbHoldFlag)
//         {
//             continue;
//         }
//         if (pOp->mScheduling->mbNGFlag)
//         {
//             continue;
//         }
//         //int inLibOrWorking = pOp->mScheduling->miInLibBoxCnt + pOp->mScheduling->mWorkingBoxID.count();
//         int inLibOrWorking = pOp->mScheduling->mBoxesInLib.miCutCnt + pOp->mScheduling->mBoxesInWork.miCutCnt;
//         //int unFinish = pOp->pOrder->miTotalPlanCnt - pOp->miFinishedCnt;
//         //if (inLibOrWorking < unFinish)
//         //{
//         //	continue;//还有一些筐没有在库或可生产，不适用这个策略
//         //}
//         if (false == pOp->mScheduling->mbAllUnDoInLib)
//         {
//             continue;
//         }

//         float totalInlibSecond = 0.0;
//         double fb = 10.0;
//         totalInlibSecond = pOp->mfProcessStdTime;
//         //totalInlibSecond *= this->preScheduling->GetProcessRealCutInLib(pOp);
//         totalInlibSecond *= (pOp->mScheduling != nullptr ? pOp->mScheduling->mBoxesInLib.miCutCnt : 0);
//         int gRuleMinBoxInLib = pSchData->hParamSet["MinInLibBoxPer"]->ValueInt();
//         int gRuleMinStdtimeInLib = pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();
//         if (pOp->mScheduling->mBoxesInLib.miBoxCnt <= gRuleMinBoxInLib)
//         {
//             fb += 10.0;
//         }
//         if (totalInlibSecond <= gRuleMinStdtimeInLib)
//         {
//             fb += 10.0;
//         }
//         fb *= ratio;


//         //if (inLibOrWorking >= unFinish)不需要限制
//         {
//             for(SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
//             {
//                 if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
//                 {
//                     continue;
//                 }
//                 if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
//                 {
//                     pScor->ScoreItem[0] = fb;
//                     pScor->Total += pScor->ScoreItem[0];
//                 }
//             }
//         }
//     }
//     return;
// }
void CSchProcessPosition::CalculateItem_1(float ratio)
{
    if (ratio < 0.01) return;

    // 添加调试信息
    qDebug() << "CalculateItem_1 开始执行，ratio:" << ratio;
    qDebug() << "hProcessSet 大小:" << this->ProcessPosition.hProcessSet.size();
    qDebug() << "hScoreByProcess 大小:" << this->ProcessPosition.hScoreByProcess.size();

    QHash<qlonglong, CJgOrderProcess*>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess* pOp = iter.value();

        // 全面的空指针检查
        if (!pOp) {
            qDebug() << "警告: 遇到空工序指针，跳过";
            continue;
        }

        if (!pOp->mScheduling) {
            qDebug() << "警告: 工序" << pOp->miProcessId << "没有调度数据，跳过";
            continue;
        }

        qDebug() << "处理工序:" << pOp->miProcessId
                 << "mbHoldFlag:" << pOp->mScheduling->mbHoldFlag
                 << "mbNGFlag:" << pOp->mScheduling->mbNGFlag
                 << "mbAllUnDoInLib:" << pOp->mScheduling->mbAllUnDoInLib;

        if (pOp->mScheduling->mbHoldFlag) {
            qDebug() << "工序" << pOp->miProcessId << "被暂停，跳过";
            continue;
        }
        if (pOp->mScheduling->mbNGFlag) {
            qDebug() << "工序" << pOp->miProcessId << "NG标志为真，跳过";
            continue;
        }

        // 检查分数表是否存在
        if (!this->ProcessPosition.hScoreByProcess.contains(iter.key())) {
            qDebug() << "警告: 工序" << iter.key() << "在分数表中不存在，跳过";
            continue;
        }

        QVector<SSCORE*>& scores = this->ProcessPosition.hScoreByProcess[iter.key()];
        if (scores.isEmpty()) {
            qDebug() << "警告: 工序" << iter.key() << "分数向量为空，跳过";
            continue;
        }

        // 继续原有逻辑...
        if (false == pOp->mScheduling->mbAllUnDoInLib) {
            qDebug() << "工序" << pOp->miProcessId << "不是全部在库，跳过项目1计算";
            continue;
        }

        float totalInlibSecond = 0.0;
        double fb = 10.0;
        totalInlibSecond = pOp->mfProcessStdTime;
        totalInlibSecond *= (pOp->mScheduling != nullptr ? pOp->mScheduling->mBoxesInLib.miCutCnt : 0);

        qDebug() << "工序" << pOp->miProcessId << "在库信息 - BoxCnt:" << pOp->mScheduling->mBoxesInLib.miBoxCnt
                 << "CutCnt:" << pOp->mScheduling->mBoxesInLib.miCutCnt
                 << "总工时:" << totalInlibSecond;

        if (pOp->mScheduling->mBoxesInLib.miBoxCnt <= gRuleMinBoxInLib) {
            fb += 10.0;
            qDebug() << "工序" << pOp->miProcessId << "在库筐数不足，加分";
        }
        if (totalInlibSecond <= gRuleMinStdtimeInLib) {
            fb += 10.0;
            qDebug() << "工序" << pOp->miProcessId << "在库工时不足，加分";
        }
        fb *= ratio;
        qDebug() << "工序" << pOp->miProcessId << "最终分数:" << fb;

        // 更新分数
        for(SSCORE* pScor : scores) {
            if (!pScor) {
                qDebug() << "警告: 遇到空分数指针，跳过";
                continue;
            }

            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position)) {
                qDebug() << "工序" << pOp->miProcessId << "工位" << pScor->Position << "不在可排产工位中，跳过";
                continue;
            }

            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position)) {
                qDebug() << "更新工序" << pOp->miProcessId << "工位" << pScor->Position << "分数:" << fb;
                pScor->ScoreItem[0] = fb;
                pScor->Total += pScor->ScoreItem[0];
            } else {
                qDebug() << "工序" << pOp->miProcessId << "工位" << pScor->Position << "不在可执行工位列表中";
            }
        }
    }

    qDebug() << "CalculateItem_1 执行完成";
}
void CSchProcessPosition::CalculateItem_2(float ratio)
{
    if (ratio < 0.01)return;
    double dMax = 0;
    double dMin = 10000000.0;
    int iNormalHour = this->pSchData->hParamSet["NormalPeriodHour"]->ValueInt();
    if (iNormalHour == 0)iNormalHour = 1;
    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }

        double fb = 0.0;
        fb = pOp->mScheduling->mNowHourTarget;
        if (fb == 0.0)fb = 1;
        double dLeftHour = 0;
        dLeftHour = pOp->pOrder->miNow2DeadlineSecs;
        dLeftHour /= 3600.0;
        //int iNormalHour = 1;
        //this->pSchData->hParamSet["NormalPeriodHour"]->GetValue(iNormalHour);

        dLeftHour /= iNormalHour;
        fb *= exp(-dLeftHour);
        if (fb > dMax)dMax = fb;
        if (fb < dMin)dMin = fb;

        for(SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                pScor->ScoreItem[1] = fb;// *ratio;
                //pScor->Total += pScor->ScoreItem[0];
            }
        }
    }

    //归一化
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for(SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                double fb = pScor->ScoreItem[1];
                double fb1 = 10.0;
                if (dMax > dMin)
                {
                    fb1 = ((fb - dMin) / (dMax - dMin) * 9.0 + 1.0) * ratio;
                }

                else
                {
                    fb1 = fb > 0 ? 10.0 * ratio : 0.0;
                }
                pScor->ScoreItem[1] = fb1 > 0 ? fb1 : 0.0;// *ratio;
                pScor->Total += pScor->ScoreItem[1];
            }
        }
    }

    return;
}

//项目3：效率优先，没有技能的工位不出现，有技能的按照技能从最高到最低10~1按比例标准化
void CSchProcessPosition::CalculateItem_3(float ratio)
{
    if (ratio < 0.01)return;
    double dMax = 0;
    double dMin = 1000000.0;

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }

        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                QString mworkerNum = pPositionManager->getWorkerNum(pScor->Position);
                if (false == mworkerNum.isEmpty())
                {
                    float fRate = pTechManger->getByCode(
                        mworkerNum, pOp->mProcessCode);
                    if (fRate != 0.0)
                    {
                        if (fRate > dMax)dMax = fRate;
                        if (fRate < dMin)dMin = fRate;
                        pScor->ScoreItem[2] = fRate;
                    }
                    else
                    {
                        pScor->ScoreItem[2] = 0;
                    }
                }
            }
        }
    }

    //归一化,需要在不同工序内归一化，才能反映一个工人最适合做什么
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                double fb = pScor->ScoreItem[2];
                double fb1 = 10.0* ratio;
                if (abs(dMax - dMin) > 0.01)
                    fb1 = ((fb - dMin) / (dMax - dMin) * 9.0 + 1.0)* ratio;
                else
                    fb1 = fb > 0 ? 10.0* ratio : 0;
                pScor->ScoreItem[2] = fb1 > 0 ? fb1 : 0.0;
                pScor->Total += pScor->ScoreItem[2];
            }
        }
    }

    return;
}

//项目4：工位连贯性，工序为工位正在做的10分，工序为工人正在做的工序相同颜色的5分，工序的订单的线号与正在做相同的5分，工序为工人正在做的相同外部订单的工序4分（溢达会同订单不同颜色），与正在做的工序类型相同2分。
void CSchProcessPosition::CalculateItem_4(float ratio)
{
    if (ratio < 0.01)return;

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }

        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                if (pOp->mScheduling->misWorkingPos.contains(pScor->Position))
                {
                    pScor->ScoreItem[3] = 10.0* ratio;
                    pScor->Total += pScor->ScoreItem[3];
                }
                else
                {
                    //找到工位当前工序
                    CJgOrderProcess * pOpTemp = this->preScheduling->GetProcessWorkingByPosition( pScor->Position);
                    if (pOpTemp == nullptr)
                    {
                        //没有当前工序不用做

                    }
                    else
                    {
                        //通过正在做的工序找当前订单
                        if (pOp->pOrder->mLocalOrderNum == pOpTemp->pOrder->mLocalOrderNum)
                        {
                            pScor->ScoreItem[3] = 6.0* ratio;
                            pScor->Total += pScor->ScoreItem[3];
                        }
                        else
                        {
                            if (pOp->pOrder->mColor == pOpTemp->pOrder->mColor)
                            {
                                pScor->ScoreItem[3] = 5.0* ratio;
                                pScor->Total += pScor->ScoreItem[3];
                            }
                            else if (pOp->pOrder->mLineColorNum == pOpTemp->pOrder->mLineColorNum)
                            {
                                pScor->ScoreItem[3] = 5.0* ratio;
                                pScor->Total += pScor->ScoreItem[3];
                            }
                            else if (pOp->pOrder->mOuterOrderNum == pOpTemp->pOrder->mOuterOrderNum)
                            {
                                pScor->ScoreItem[3] = 4.0 * ratio;
                                pScor->Total += pScor->ScoreItem[3];
                            }
                            else if (pOp->mProcessType == pOpTemp->mProcessType
                                     && pOp->mProcessType.length() > 0)
                            {
                                pScor->ScoreItem[3] = 2.0 * ratio;
                                pScor->Total += pScor->ScoreItem[3];
                            }
                        }
                    }
                }
            }
        }
    }
    return;
}

//项目5：订单连贯性，下道工序正在做的工人数x人均最小在库工时 - 下道工序在库产量工时 -这道工序正在的工人数x1800,得到原始分之后在标准化为0~10分，如果下道工序是出库，直接给20分
void CSchProcessPosition::CalculateItem_5(float ratio)
{
    if (ratio < 0.01)return;
    double dMax = -10000000000.0;
    double dMin = 10000000000.0;
    //int iSTD = this->pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        double fbInProcess = 0.0;
        int workingPosCNT = 0;
        workingPosCNT = pOp->mScheduling->misWorkingPos.count();
        double dbNextProcInLib = 0.0;
        int iNextProcPos = 0;
        /*QSet<CJgOrderProcess *> AfterProcessSet =
            CPreScheduling::FindAfterProcess(pSchData, pOp->pOrder->mOrderProcessSetGroupByPart[pOp->mPartName], pOp);*/
        if (pOp->mDepandency.DirectTo.count() == 0)
        {
            fbInProcess = -987654321.12345;
        }
        for (CJgOrderProcess * nextProcess : pOp->mDepandency.DirectTo)
        {
            if (nextProcess->IsOutLine() ||
                nextProcess->IsInterrupt() ||
                nextProcess->IsSecondPackup() ||
                nextProcess->IsSendOut())
            {
                fbInProcess = -987654321.12345;
                break;
            }
            //int inLibOrWorking = nextProcess->mScheduling->miInLibBoxCnt + pOp->mScheduling->mWorkingBoxID.count();
            int workingPosCntNextProcess = nextProcess->mScheduling->misWorkingPos.count();
            //double dbf1 = this->preScheduling->GetProcessRealCutInLib(nextProcess);
            double dbf1 = nextProcess->mScheduling != nullptr ? nextProcess->mScheduling->mBoxesInLib.miCutCnt : 0.0;
            dbf1 *= nextProcess->mfProcessStdTime;
            dbNextProcInLib += dbf1;
            if (workingPosCntNextProcess == 0)
            {//如果没有人在做，系统希望有一个人在做
                workingPosCntNextProcess = 1;
            }
            iNextProcPos += workingPosCntNextProcess;
            //int iSTD = 0;
            //this->pSchData->hParamSet["MinInLibSTDPer"]->GetValue(iSTD);
            //double dbf2 = workingPosCntPreProcess * iSTD;
            //double dbf3 = workingPosCNT * iSTD;
            //dbf1 = dbf2 - dbf1 - dbf3;
            //if (dbf1 > fbInProcess)fbInProcess = dbf1;
            /*dbf1 -= (workingPosCntPreProcess - workingPosCNT)*iSTD;
            if (dbf1 > fbInProcess) fbInProcess = dbf1;*/
        }

        if (fbInProcess != -987654321.12345)
        {
            //int iSTD = 0;
            //this->pSchData->hParamSet["MinInLibSTDPer"]->GetValue(iSTD);
            double dbf2 = iNextProcPos * gRuleMinStdtimeInLib;
            double dbf3 = workingPosCNT * gRuleMinStdtimeInLib;
            fbInProcess = dbf2 - dbNextProcInLib - dbf3;

            if (dMax < fbInProcess)
            {
                dMax = fbInProcess;
            }
            if (dMin > fbInProcess)
            {
                dMin = fbInProcess;
            }
            for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
            {
                if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
                {
                    pScor->ScoreItem[4] = 123456789.987654321;
                    continue;
                }
                if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
                {
                    pScor->ScoreItem[4] = fbInProcess;
                }
            }
        }
        else
        {
            for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
            {
                if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
                {
                    pScor->ScoreItem[4] = 1234567.98765;
                    continue;
                }
                if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
                {
                    pScor->ScoreItem[4] = 20.0;
                    //pScor->Total += pScor->ScoreItem[4];
                }
            }
        }
    }

    //归一化,需要在不同工序内归一化，才能反映一个工人最适合做什么
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                pScor->ScoreItem[4] = 0.0;
                continue;
            }
            if (pScor->ScoreItem[4] == 123456789.987654321)
            {
                pScor->ScoreItem[4] = 0.0;
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                if (pScor->ScoreItem[4] == 1234567.98765)
                {
                    pScor->ScoreItem[4] = 0.0;
                    continue;
                }
                if (pScor->ScoreItem[4] != 20.0)
                {
                    double fb = pScor->ScoreItem[4];
                    double fb1 = 10.0* ratio;
                    if (abs(dMax - dMin) > 0.01)
                        fb1 = ((fb - dMin) / (dMax - dMin) * 9.0 + 1.0)* ratio;
                    else
                        fb1 = 10.0* ratio;
                    pScor->ScoreItem[4] = fb1 > 0 ? fb1 : 0.0;
                    pScor->Total += pScor->ScoreItem[4];
                }
                else
                {
                    pScor->ScoreItem[4] = 20.0 * ratio;
                    pScor->Total += pScor->ScoreItem[4];
                }
            }
        }
    }

    return;
}


//项目6：库存连贯性，库存产量工时大于1800/人且在库数量大于3/人，分数=10；库存产量工时大于1800/人，分数=8；库存产量工时大于1800，分数=5；在库筐数大于3筐，分数=2，其他分数=0
void CSchProcessPosition::CalculateItem_6(float ratio)
{
    if (ratio < 0.01)return;
    //int iSTD = 0;
    //int iMinInLibBox = 0;
    //iSTD = this->pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();
    //iMinInLibBox = this->pSchData->hParamSet["MinInLibBoxPer"]->ValueInt();

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }


        int workingPosCNT = 0;
        workingPosCNT = pOp->mScheduling->misWorkingPos.count();
        if (pOp->mScheduling->mBoxesInLib.miBoxCnt > 0 && pOp->mScheduling->mBoxesInWork.miBoxCnt > 0)
        {
            //库里有且有在做的，认为需要延续，以满分计算
            for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
            {
                if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
                {
                    continue;
                }
                if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
                {
                    if (pOp->mScheduling->misWorkingPos.contains(pScor->Position))
                    {
                        pScor->ScoreItem[5] = 20.0;
                        //后面用来判断不要被普通的分数刷新掉pScor->Total += pScor->ScoreItem[5];
                    }
                }
            }
            continue;
        }
        int inLibBox = pOp->mScheduling->mBoxesInLib.miBoxCnt;
        //double dbf = this->preScheduling->GetProcessRealCutInLib(pOp);
        double dbf = pOp->mScheduling != nullptr ? pOp->mScheduling->mBoxesInLib.miCutCnt : 0.0;
        dbf *= pOp->mfProcessStdTime;
        int inLibBoxPerPos = inLibBox;
        double dbf1 = dbf;
        if (workingPosCNT > 0)
        {
            inLibBoxPerPos /= workingPosCNT;
            dbf1 /= workingPosCNT;
        }
        /*int iSTD = 0;
        int iMinInLibBox = 0;
        this->pSchData->hParamSet["MinInLibSTDPer"]->GetValue(iSTD);
        this->pSchData->hParamSet["MinInLibBoxPer"]->GetValue(iMinInLibBox);*/
        int iScore = 0;
        if ((inLibBoxPerPos >= gRuleMinBoxInLib) && (dbf1 >= gRuleMinStdtimeInLib))
        {
            iScore = 10;
        }
        else if (dbf1 >= gRuleMinStdtimeInLib)
        {
            iScore = 8;
        }
        else if (dbf >= gRuleMinStdtimeInLib)
        {
            iScore = 5;
        }
        else if (inLibBox >= gRuleMinBoxInLib)
        {
            iScore = 2;
        }

        double dbf2 = iScore;
        dbf2 *= ratio;
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                if (abs(pScor->ScoreItem[5] - 20.0) > 0.001)
                {
                    pScor->ScoreItem[5] = dbf2;
                }
                else
                {
                    pScor->ScoreItem[5] *= ratio;
                }
                pScor->Total += pScor->ScoreItem[5];
            }
        }
    }
    return;
}

//项目7：紧急标志，订单紧急时分数1000
void CSchProcessPosition::CalculateItem_7(float ratio)
{
    if (ratio < 0.01)return;

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        /*if (pOp->mScheduling->mBoxesInLib.miBoxCnt == 0)
        {
            continue;
        }*/
        if (pOp->mScheduling->mbUrgentFlag)
        {
            double dbf = 1000.0;
            dbf *= ratio;
            for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
            {
                if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
                {
                    continue;
                }

                if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
                {
                    pScor->ScoreItem[6] = dbf;
                    pScor->Total += pScor->ScoreItem[6];
                }
            }
        }
    }
    return;
}

void CSchProcessPosition::CalculateItem_8(float ratio)
{
    if (ratio < 0.01)return;

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }

        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                double dbf = 0.0;
                int iStatus = pPositionManager->getStatus(pScor->Position);
                if (iStatus == -1)continue;
                if (iStatus == FREE_P_S)
                {
                    dbf = 10.0;
                }
                else
                {
                    CJgOrderProcess * pOpTemp = this->preScheduling->GetProcessWorkingByPosition(pScor->Position);
                    int inLibCNT = 0;
                    if ((pOpTemp != nullptr) && (pOpTemp->mProcessCode != pOp->mProcessCode))
                    {
                        //inLibCNT = this->preScheduling->GetProcessRealCutInLib(pOpTemp);
                        inLibCNT = pOpTemp->mScheduling != nullptr ? pOpTemp->mScheduling->mBoxesInLib.miBoxCnt : 0;
                    }
                    if (pOpTemp == nullptr)
                    {
                        dbf = 10.0;
                    }
                    else if (pOpTemp->mProcessCode == pOp->mProcessCode)
                    {
                        dbf = 10.0;
                    }
                    else if (inLibCNT > 0)
                    {
                        dbf = 0.0;
                    }
                    else if (iStatus == IN_PRO_ONLY_P_S)
                    {
                        dbf = 8.0;
                    }
                    else if (iStatus == WAITING_FOR_ONLY_PRO_P_S)
                    {
                        dbf = 3.0;
                    }
                    else if (iStatus == IN_THE_WAY_P_S)
                    {
                        dbf = 2.0;
                    }
                    else if (iStatus == BUSY_P_S)
                    {
                        dbf = 1.0;
                    }

                }

                pScor->ScoreItem[7] = dbf * ratio;
                pScor->Total += pScor->ScoreItem[7];
            }
        }
    }
    return;
}

void CSchProcessPosition::CalculateItem_9(float ratio)
{
    //用实际的小时任务数成衣每件标准工时，得到当前的小时需要多少标准工时
    double dbOnHour = 0.0;
    double dbWorkerHour = 0.0;
    double dMax = 0.0;
    double dMin = 0.0;

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->miProcessAttri != 0)
        {
            continue;
        }
        if (false == pOp->IsNormal())
        {
            continue;
        }

        pOp->mScheduling->mIncDecFlag = 0;
        dbOnHour = pOp->mfProcessStdTime * pOp->mScheduling->mNowHourTarget;
        dbWorkerHour = pOp->mScheduling->misWorkingPos.count() * gRuleAddPosSTD;
        double dbDiff = dbOnHour - dbWorkerHour;
        if (dbDiff > 0.0)
        {
            if (dbDiff > dMax)
            {
                dMax = dbDiff;
            }
            for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
            {
                if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
                {
                    continue;
                }
                if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
                {
                    pScor->ScoreItem[8] = dbDiff;
                }
            }
            if (dbDiff > gRuleAddPosSTD * 7.0)
            {
                pOp->mScheduling->mIncDecFlag = 6;
            }
            else if (dbDiff > gRuleAddPosSTD * 6.0)
            {
                pOp->mScheduling->mIncDecFlag = 6;
            }
            else if (dbDiff > gRuleAddPosSTD * 5.0)
            {
                pOp->mScheduling->mIncDecFlag = 5;
            }
            else if (dbDiff > gRuleAddPosSTD * 4.0)
            {
                pOp->mScheduling->mIncDecFlag = 4;
            }
            else if (dbDiff > gRuleAddPosSTD * 3.0)
            {
                pOp->mScheduling->mIncDecFlag = 3;
            }
            else if (dbDiff > gRuleAddPosSTD * 2.0)
            {
                pOp->mScheduling->mIncDecFlag = 2;
            }
            else if (dbDiff > gRuleAddPosSTD * 1.0)
            {
                pOp->mScheduling->mIncDecFlag = 1;
            }
            else if (pOp->mScheduling->misWorkingPos.count() == 0)
            {
                pOp->mScheduling->mIncDecFlag = 1;
            }
        }
        else if (dbDiff < -0.0)
        {
            if (dbDiff < dMin)
            {
                dMin = dbDiff;
            }
            for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
            {
                if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
                {
                    continue;
                }
                if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
                {
                    pScor->ScoreItem[8] = dbDiff;
                }
            }
            if ((pOp->mScheduling->mNowHourTarget > 0) && (pOp->mScheduling->misWorkingPos.count() == 1))
            {
                pOp->mScheduling->mIncDecFlag = 0;
            }
            else if (pOp->mScheduling->misWorkingPos.count() == 0)
            {
                pOp->mScheduling->mIncDecFlag = 0;
            }
            else if ((pOp->mScheduling->misWorkingPos.count() == 1))
            {
                if (dbDiff < gRuleAddPosSTD * (-2.0))
                {
                    pOp->mScheduling->mIncDecFlag = -1;
                }
            }
            else if (dbDiff < gRuleAddPosSTD * (-1.5))
            {
                pOp->mScheduling->mIncDecFlag = -1;
            }
        }
        else
        {

        }

        /*98、全部在库，小于最小筐数或小于最小标准工时，在做的人等于0要求加减人标志1，在做的人等于1要求加人标志 = 0，在做的人大于1允许加人标志 = -1
            98.1、检查在计算加人标志CalculateItem_9之前已经有了在做工位数据。
            98.2、检查符合全部在库判断和最小数据。否则按原先计算值
            98.3、检查在产人数大于1的，按原先计算值
            98.4、在产人数 = 1的，如果计算值小于零，直接给成0
            98.5、在产人数 = 0的，如果计数值小于1，直接给成1*/
        if (pOp->mScheduling->mbAllUnDoInLib)
        {
            if ((pOp->mScheduling->mBoxesInLib.miBoxCnt <= gMinBoxInLibAddPosition)
                ||
                ((pOp->mScheduling->mBoxesInLib.miCutCnt * pOp->mfProcessStdTime) <= gRuleMinStdtimeInLib))
            {
                if (pOp->mScheduling->misWorkingPos.count() == 0)
                {
                    if (pOp->mScheduling->mIncDecFlag < 1)
                    {
                        pOp->mScheduling->mIncDecFlag = 1;
                    }
                }
                else if (pOp->mScheduling->misWorkingPos.count() == 1)
                {
                    if (pOp->mScheduling->mIncDecFlag < 0)
                    {
                        pOp->mScheduling->mIncDecFlag = 0;
                    }
                }
            }
        }
    }

    //进行归一化并处理工位不同状态的系数关系
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                if (pScor->ScoreItem[8] > 0)
                {
                    pScor->ScoreItem[8] = ((10.0 - gBalanceLevel) * pScor->ScoreItem[8]) / dMax;
                    if (pOp->mScheduling->misWorkingPos.contains(pScor->Position))
                    {
                        pScor->ScoreItem[8] *= 1.0;
                    }
                    else if (pOp->mScheduling->mPlanPositions.contains(pScor->Position))
                    {
                        pScor->ScoreItem[8] *= 0.9;
                    }
                    else if (pOp->mScheduling->misHaveDonePos.contains(pScor->Position))
                    {
                        pScor->ScoreItem[8] *= 0.75;
                    }
                    else
                    {
                        pScor->ScoreItem[8] *= 0.5;
                    }
                    pScor->ScoreItem[8] += gBalanceLevel;
                }
                else if (pScor->ScoreItem[8] < 0)
                {
                    pScor->ScoreItem[8] = (-gBalanceLevel * pScor->ScoreItem[8]) / dMin;
                    if (pOp->mScheduling->mPlanPositions.contains(pScor->Position))
                    {
                        pScor->ScoreItem[8] *= 1.0;
                    }
                    else if (pOp->mScheduling->misWorkingPos.contains(pScor->Position))
                    {
                        pScor->ScoreItem[8] *= 0.8;
                    }
                    else
                    {
                        pScor->ScoreItem[8] *= 0.7;
                    }
                    pScor->ScoreItem[8] += gBalanceLevel;
                }
                else
                {
                    pScor->ScoreItem[8] = gBalanceLevel;
                }

                double fb = pScor->ScoreItem[8];
                double fb1 = fb * ratio;
                pScor->ScoreItem[8] = fb1 > 0 ? fb1 : 0.0;
                pScor->Total += pScor->ScoreItem[8];
            }
        }
    }
}

//黑名单
void CSchProcessPosition::CalculateItem_10(float ratio)
{
    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }

        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->misBlackList.contains(pScor->Position))
            {
                pScor->ScoreItem[9] = -pScor->Total;
                pScor->Total =0.0;
            }
        }
    }
}

void CSchProcessPosition::CalculateItem_11(float ratio)
{
    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }


        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                qlonglong currentProcessID = pPositionManager->getCurrentProcessID(pScor->Position);
                if (currentProcessID != -1)
                {
                    if (pOp->miProcessId == currentProcessID)
                    {

                    }
                    else
                    {
                        pScor->ScoreItem[10] = 10.0;
                    }
                }
            }
        }
    }
}

void CSchProcessPosition::CalculateItem_12(float ratio)
{

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                /*CJgPosition pos;
                pos = theApp.pRIR->pPositionManager->getPosition(pScor->Position);*/
                QStringList machineTypes = pPositionManager->getMachineType(pScor->Position);
                if (machineTypes.count() == _MAX_POSITION_MACHINE_TYPE_NUM_)
                {
                    for (int i = 0; i < _MAX_POSITION_MACHINE_TYPE_NUM_; i++)
                    {
                        if (machineTypes.at(i) == pOp->mMachineType)
                        {
                            if (false == machineTypes.at(i).isEmpty())
                            {
                                pScor->ScoreItem[11] = 10.0 / _MAX_POSITION_MACHINE_TYPE_NUM_ * (_MAX_POSITION_MACHINE_TYPE_NUM_ - i) * ratio;
                                pScor->Total += pScor->ScoreItem[11];
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}

void CSchProcessPosition::CalculateItem_13(float ratio)
{

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                if (pOp->mScheduling->misHaveDonePos.contains(pScor->Position))
                {
                    pScor->ScoreItem[12] = 10.0 * ratio;
                    pScor->Total += pScor->ScoreItem[12];
                }
            }
        }
    }
}

//项目14：工序类型效率优先，没有技能的工位不出现，有技能的按照技能从最高到最低10~1按比例标准化
void CSchProcessPosition::CalculateItem_14(float ratio)
{
    if (ratio < 0.01)return;
    double dMax = 0;
    double dMin = 1000000.0;

    QHash<qlonglong/*工序id*/, CJgOrderProcess * /*工序数据指针*/>::iterator iter;
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }

        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                QString sWorkerNum = pPositionManager->getWorkerNum(pScor->Position);
                if (false == sWorkerNum.isEmpty())
                {
                    float fRate = pTechManger->getByType(
                        sWorkerNum, pOp->mProcessType);
                    if (fRate != 0.0)
                    {
                        if (fRate > dMax)dMax = fRate;
                        if (fRate < dMin)dMin = fRate;
                        pScor->ScoreItem[13] = fRate;
                    }
                    else
                    {
                        pScor->ScoreItem[13] = 0;
                    }
                }
            }
        }
    }

    //归一化,需要在不同工序内归一化，才能反映一个工人最适合做什么
    for (iter = this->ProcessPosition.hProcessSet.begin();
         iter != this->ProcessPosition.hProcessSet.end(); ++iter)
    {
        CJgOrderProcess * pOp = iter.value();
        if (pOp->mScheduling->mbHoldFlag)
        {
            continue;
        }
        if (pOp->mScheduling->mbNGFlag)
        {
            continue;
        }
        for (SSCORE* pScor : this->ProcessPosition.hScoreByProcess[iter.key()])
        {
            if (!this->ProcessPosition.sPositionsScore.contains(pScor->Position))
            {
                continue;
            }
            if (pOp->mScheduling->mPosCanDo.contains(pScor->Position))
            {
                double fb = pScor->ScoreItem[13];
                double fb1 = 10.0* ratio;
                if (abs(dMax - dMin) > 0.01)
                    fb1 = ((fb - dMin) / (dMax - dMin) * 9.0 + 1.0)* ratio;
                else
                    fb1 = fb > 0 ? 10.0* ratio : 0;
                pScor->ScoreItem[13] = fb1 > 0 ? fb1 : 0.0;
                pScor->Total += pScor->ScoreItem[13];
            }
        }
    }

    return;
}

bool CSchProcessPosition::FaKuang_MinSTD(SSCORE * s, QString why)
{
    QString checkAnswer;
    if (s->pOp == nullptr)
    {
        why = "无效订单工序数据；";
        QString ss;
        ss = QString("数据版本%1，不发出工序（未知）给工位%2,原因无效订单工序数据")
                 .arg(this->ProcessPosition.Version).arg(s->Position);
        s->remark += why;
        return false;
    }
    if (s->pOp->pOrder == nullptr)
    {
        why = "订单工序数据无法指向订单；";
        QString ss;
        ss = QString("数据版本%1，不发出工序（未知）给工位%2,原因订单工序数据无法指向订单")
                 .arg(this->ProcessPosition.Version).arg(s->Position);
        s->remark += why;
        return false;
    }
    if (false == ReCheckCanSend_MinSTD(s, checkAnswer))
    {
        s->remark += checkAnswer;
        QString ss;
        ss = QString("数据版本%8，不发出工序（订单%1（%2），部件%3，简称%4（%5））给工位%6,原因%7")
                 .arg(s->pOp->pOrder->mLocalOrderNum).arg(s->pOp->pOrder->mOuterOrderNum).arg(s->pOp->mPartName)
                 .arg(s->pOp->mProcessBrief).arg(s->pOp->miPartSeqNum).arg(s->Position).arg(s->remark).arg(this->ProcessPosition.Version);
        return false;
    }
    // s->remark += checkAnswer;
    // checkAnswer = "";
    // if (false == RecheckCanSend_QieHuan(s, checkAnswer))
    // {
    //     s->remark += checkAnswer;
    //     QString ss;
    //     ss = QString("数据版本%8，不发出工序（订单%1（%2），部件%3，简称%4（%5））给工位%6,原因%7")
    //              .arg(s->pOp->pOrder->mLocalOrderNum).arg(s->pOp->pOrder->mOuterOrderNum).arg(s->pOp->mPartName)
    //              .arg(s->pOp->mProcessBrief).arg(s->pOp->miPartSeqNum).arg(s->Position).arg(s->remark).arg(this->ProcessPosition.Version);
    //     return false;
    // }
    s->remark += checkAnswer;
    checkAnswer = "";
    if (false == RecheckCanSend_WeiChi(s, checkAnswer))
    {
        s->remark += checkAnswer;
        QString ss;
        ss = QString("数据版本%8，不发出工序（订单%1（%2），部件%3，简称%4（%5））给工位%6,原因%7")
                 .arg(s->pOp->pOrder->mLocalOrderNum).arg(s->pOp->pOrder->mOuterOrderNum).arg(s->pOp->mPartName)
                 .arg(s->pOp->mProcessBrief).arg(s->pOp->miPartSeqNum).arg(s->Position).arg(s->remark).arg(this->ProcessPosition.Version);
        return false;
    }
    s->remark += checkAnswer;
    checkAnswer = "";
    if ((true == IsAllUndoInLibAndFew(s->pOp))
        &&(false == RecheckCanSend_QuanBuZaiKu(s, checkAnswer)))
    {
        s->remark += checkAnswer;
        QString ss;
        ss = QString("数据版本%8，不发出工序（订单%1（%2），部件%3，简称%4（%5））给工位%6,原因%7")
                 .arg(s->pOp->pOrder->mLocalOrderNum).arg(s->pOp->pOrder->mOuterOrderNum).arg(s->pOp->mPartName)
                 .arg(s->pOp->mProcessBrief).arg(s->pOp->miPartSeqNum).arg(s->Position).arg(s->remark).arg(this->ProcessPosition.Version);
        return false;
    }
    s->remark += checkAnswer;
    checkAnswer = "";

    //允许待产等待，如果在产有工作，换工序需要工位分数的排序在加人数目以内，不如工序现在一个人在做，需要加一个人，如果工位在工序的排序是第二位，则可发，如果是第三名，不可发。等待在产已经完成，如果加人没有加到第二名，这时候才可以发给第三名的工位。
    if ((1 == gRuleWaitForBestPair/*this->pSchData->hParamSet["WaitForBestPair"]->ValueInt() == 1*/)
        && (false == RecheckCanSend_WaitBest(s, checkAnswer)))
    {
        s->remark += checkAnswer;
        QString ss;
        ss = QString("数据版本%8，不发出工序（订单%1（%2），部件%3，简称%4（%5））给工位%6,原因%7")
                 .arg(s->pOp->pOrder->mLocalOrderNum).arg(s->pOp->pOrder->mOuterOrderNum).arg(s->pOp->mPartName)
                 .arg(s->pOp->mProcessBrief).arg(s->pOp->miPartSeqNum).arg(s->Position).arg(s->remark).arg(this->ProcessPosition.Version);
        return false;
    }
    s->remark += checkAnswer;
    checkAnswer = "";


    return true;
}

bool CSchProcessPosition::ReCheckCanSend_MinSTD(SSCORE * s, QString &why)
{
    if (gRuleReCheckCanSendMinStdInLib == 0)
    {
        return true;
    }
    if (s->pOp == nullptr)
    {
        why = "无效订单工序数据；";
        return false;
    }
    if (s->pOp->mScheduling == nullptr)
    {
        why = "无效订单工序排产数据；";
        return false;
    }
    float stdInLib = s->pOp->mScheduling->mBoxesInLib.miCutCnt;
    stdInLib *= s->pOp->mfProcessStdTime;
    int workerPos = 0;
    int BoxPerPosition = 0;
    workerPos = s->pOp->mScheduling->misWorkingPos.count();
    if (false == s->pOp->mScheduling->misWorkingPos.contains(s->Position))
    {
        workerPos++;
    }
    //int minStdPer = this->pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();
    //int minBoxPer = this->pSchData->hParamSet["MinInLibBoxPer"]->ValueInt();
    //最后n筐不考虑在库工时的条件还要加上当前没人在做这个工序，
    /*bool isLastNboxInLib = (s->pOp->mScheduling->mBoxesInLib.miCutCnt +
                            s->pOp->mScheduling->mBoxesInWork.miCutCnt+
                            s->pOp->miFinishedCnt) >=
                            s->pOp->pOrder->miTotalPlanCnt;
    本工序回库的上面算不了*/
    //bool isLastNboxInLib = this->IsAllUndoInLib(s->pOp->miProcessId);
    BoxPerPosition = s->pOp->mScheduling->mBoxesInLib.miBoxCnt / workerPos;

    if ((stdInLib / workerPos) >= gRuleMinStdtimeInLib)
    {
        why = QString("人均可做在库工时（%1）大于设置值（%2），允许发筐；").arg(stdInLib / workerPos).arg(gRuleMinStdtimeInLib);
        return true;
    }

    if (BoxPerPosition >= gRuleMinBoxInLib)
    {
        why = QString("人均可做在库筐数（%1）大于设置值（%2），允许发筐；").arg(BoxPerPosition).arg(gRuleMinBoxInLib);
        return true;
    }

    //70、人均在库筐数和工时不足，自己正在做也不能发，不然ZZZ的主动减人功能没能实现。
    /*if (s->pOp->mScheduling->misWorkingPos.contains(s->Position))
    {
        why = "人均在库工时或筐数不足，自己正在做的工序，允许发筐；";
        return true;
    }*/

    //到此：人均在库工时或筐数不足，不是正在做的工序，
    //70、已经不能判断不是正在做的工序了，也不能认定正在做别的工序
    bool Send2Otther = false;
    bool Send2Me = false;
    if (s->pOp->pOrder == nullptr)
    {
        why = "订单工序数据无法指向订单；";
        return false;
    }
    QVector<CJgBoxData *> boxes;
    if (s->pOp->pOrder->mCurBoxSetGroupByPart.contains(s->pOp->mPartName))
    {
        boxes = s->pOp->pOrder->mCurBoxSetGroupByPart[s->pOp->mPartName];
    }

    for (CJgBoxData * pBox : boxes)
    {
        //if ((pBox->miBoxStatus == BACK_LIB_B_S || pBox->miBoxStatus == SEND_PRO_B_S
        //	|| pBox->miBoxStatus == WAITING_FOR_PRO_B_S || pBox->miBoxStatus == IN_PRO_B_S)
        //	&& (pBox->miPartSeqNum == s->pOp->miPartSeqNum))
        int iBoxPos = pBox->mStatusInfo.toInt();
        if (iBoxPos < 1 || iBoxPos > gTotalPositionNum)continue;
        if(!s->pOp->mScheduling->mPosCanDo.contains(iBoxPos))continue;
        /*CJgPosition posObj;
        posObj = theApp.pRIR->pPositionManager->getPosition(iBoxPos);*/
        int posStatus = pPositionManager->getStatus(iBoxPos);
        if (posStatus == -1)
        {
            continue;
        }
        if ((pBox->miBoxStatus == SEND_PRO_B_S
             || pBox->miBoxStatus == WAITING_FOR_PRO_B_S)
            && (pBox->miPartSeqNum == s->pOp->miPartSeqNum))
        {
            if (iBoxPos != s->Position)
            {
                Send2Otther = true;
            }
            else
            {
                Send2Me = true;
            }
        }
        else if ((pBox->miBoxStatus == IN_PRO_B_S)
                 && (pBox->miPartSeqNum == s->pOp->miPartSeqNum)
                 && (posStatus == IN_PRO_ONLY_P_S))
        {
            if (iBoxPos != s->Position)
            {
                Send2Otther = true;
            }
            else
            {
                Send2Me = true;
            }
        }
        else if ((pBox->miBoxStatus == BACK_LIB_B_S)
                 && (pBox->miPartSeqNum == s->pOp->miPartSeqNum)
                 && (posStatus == FREE_P_S))
        {
            if (iBoxPos != s->Position)
            {
                Send2Otther = true;
            }
            else
            {
                Send2Me = true;
            }
        }
    }


    //71、"人均在库工时或筐数不足，自己刚做完的工序，自己已经空闲，允许发筐；";要求先是没人在做。
    //if ((Send2Me) && (pSchData->pPositions.at(s->Position - 1)->miPosStatus == FREE_P_S))
    //{
    //	why = "人均在库工时或筐数不足，自己刚做完的工序，自己已经空闲，允许发筐；";
    //	return true;
    //}

    //到此：人均在库工时或筐数不足，不是正在做的工序，也不是自己刚刚做完，自己也不是空闲着
    if (s->pOp->mScheduling->misWorkingPos.count() > 0)
    {
        if (false == s->pOp->mScheduling->misWorkingPos.contains(s->Position))
        {
            why = "人均在库工时和筐数不足，有别人正在做，不允许发筐；";
            return false;
        }
        else if(s->pOp->mScheduling->misWorkingPos.count() == 1)
        {
            why = "人均在库工时和筐数不足，只有自己正在做，允许发筐；";
            return true;
        }
        else
        {
            why = "人均在库工时和筐数不足，不是只有自己正在做，不允许发筐；";
            return false;
        }
    }

    //至此：没有正在做的工位
    if (Send2Otther)
    {
        why = "人均在库工时和筐数不足，有别人刚做完的工序，不允许发筐；";
        return false;
    }

    //到此：人均在库工时或筐数不足，不是正在做的工序，没有人（包括自己）在做，也没有人（包括自己）刚刚做完
    //71、到此：人均在库工时或筐数不足，没有人（包括自己）在做，也没有别人刚刚做完

    if (false == s->pOp->mScheduling->mbAllUnDoInLib)
    {
        why = QString("人均在库工时和筐数不足,没有人正在做和没有别人刚刚做完，不是剩下筐都在库，不允许发筐；");
        return false;
    }

    //到此：人均在库工时或筐数不足，不是正在做的工序，没有人正在做或刚刚做完，剩下的全部在库
    if (s->pOp->mScheduling->misHaveDonePos.contains(s->Position) || Send2Me)
    {
        why = "人均在库工时和筐数不足，剩下的全部在库，没人在做，没别人刚刚做完，自己做过或刚刚做完，允许发筐；";
        return true;
    }

    if ((s->pOp->mScheduling->misHaveDonePos.count() == 0) && (false == Send2Otther))
    {
        why = "人均在库工时或筐数不足，剩下的全部在库，没人在做或刚刚做完，没有人做过，允许发筐；";
        return true;
    }

    why = "人均在库工时或筐数不足，剩下的全部在库，没人在做或刚刚做完，有人做过不是自己，不允许发筐；";

    return false;
}

//切换工序前，正在做的工序是不是可以维持不变
bool CSchProcessPosition::RecheckCanSend_WeiChi(SSCORE * s, QString &why)
{
    if (s->pOp == nullptr)
    {
        why = "无效订单工序数据；";
        return false;
    }

    //找到工位当前在做的工序
    CJgOrderProcess * pOpTemp = this->preScheduling->GetProcessWorkingByPosition(s->Position);
    if (pOpTemp == nullptr)
    {
        why = "当前维持判断，没有当前工序，可以换；";
        return true;
    }

    if (pOpTemp->miProcessId == s->pOp->miProcessId)
    {
        why = "当前维持判断，没有更换工序，可以继续做；";
        return true;
    }

    /*CJgPosition posObj;
    posObj = theApp.pRIR->pPositionManager->getPosition(s->Position);
    if (posObj.miPosNum != s->Position)*/
    int posStatus = pPositionManager->getStatus(s->Position);
    if (posStatus == -1)
    {
        why = "当前维持判断，无法确定工位数据；";
        return false;
    }
    //工位在产空可以换
    if (posStatus == FREE_P_S)
    {
        why = "当前维持判断，绝对空闲可以换；";
        return true;
    }

    if (pOpTemp->mScheduling && (pOpTemp->mScheduling->mIncDecFlag >= 0) && (pOpTemp->mScheduling->mBoxesInLib.miBoxCnt > 0))
    {
        why = "当前维持判断，当前工序不需要减人且有在库可发，必须继续做不可换；";
        return false;
    }

    if (pOpTemp->mScheduling && (pOpTemp->mScheduling->mIncDecFlag >= 0) && (false == pOpTemp->mScheduling->mbAllUnDoNotReady))
    {
        why = "当前维持判断，当前工序不需要减人且即将有回库筐，必须继续做不可换；";
        return false;
    }
    QDateTime startTime = pPositionManager->getCurProStart(s->Position);
    int span = startTime.secsTo(QDateTime::currentDateTime());
    if (span < gRulePositionContinueOneProcessSecond)
    {
        if (pOpTemp->mScheduling->mBoxesInLib.miBoxCnt > 0)
        {
            why = QString("当前维持判断，当前工序有在库且持续时间(%1)不到最小期望时间(%2)，不可以切换；").arg(span).arg(gRulePositionContinueOneProcessSecond);
            return false;
        }
    }



    //检查当前工序是不是最后n筐
    /*bool isLastNboxInLib = (pOpTemp->mScheduling->mBoxesInLib.miCutCnt +
        pOpTemp->mScheduling->mBoxesInWork.miCutCnt +
        pOpTemp->miFinishedCnt) >=
        pOpTemp->pOrder->miTotalPlanCnt;
    上面本工序做完在回库的没计算进去，用下面的*/
    //bool isLastNboxInLib = this->IsAllUndoInLib(pOpTemp->miProcessId);
    if (false == pOpTemp->mScheduling->mbAllUnDoInLib)
    {
        why = "当前维持判断，当前工序不是全部在库，可以换；";
        return true;
    }

    if (pOpTemp->mScheduling->mBoxesInLib.miBoxCnt == 0)
    {
        why = "当前维持判断，当前工序是全部在库但是已经做完了，可以换；";
        return true;
    }
    //int minStdPer = this->pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();
    float stdInLib = pOpTemp->mScheduling->mBoxesInLib.miCutCnt;
    stdInLib *= pOpTemp->mfProcessStdTime;
    if (gRuleMinStdtimeInLib >= stdInLib)
    {
        why = "当前维持判断，当前工序是全部在库且总工时小于人均最小标准工时，不可以切换；";
        return false;
    }

    if (gRuleMinBoxInLib >= pOpTemp->mScheduling->mBoxesInLib.miCutCnt)
    {
        why = "当前维持判断，当前工序是全部在库且筐数小于人均最小筐数，不可以切换；";
        return false;
    }

    why = "当前维持判断，当前工序是全部在库但总工时大于人均最小标准工时，可以切换；";
    return true;
}

//切换工序前，如果是全部在库，判断是否工位做过本工序，只发给做过本工序的
bool CSchProcessPosition::RecheckCanSend_QuanBuZaiKu(SSCORE * s, QString &why)
{
    //if (0 == this->pSchData->hParamSet["AllInLibOnlyHaveDone"]->ValueInt())
    if(0 == gRuleAllInLibOnlyHaveDone)
    {
        return true;
    }
    if (s->pOp == nullptr)
    {
        why = "无效订单工序数据；";
        return false;
    }
    if (s->pOp->mScheduling == nullptr)
    {
        why = "无效订单工序排产数据；";
        return false;
    }

    QList<int> list = s->pOp->mScheduling->misHaveDonePos.toList();
    QSet<int> sDoneDoing(list.begin(), list.end());

    QList<int> misWorkingPosList = s->pOp->mScheduling->misWorkingPos.toList();
    QSet<int> workingSet(misWorkingPosList.begin(), misWorkingPosList.end());
    sDoneDoing.unite(workingSet);

    QList<int> posCanDoList = s->pOp->mScheduling->mPosCanDo.toList();
    QSet<int> posCanDoSet(posCanDoList.begin(), posCanDoList.end());
    sDoneDoing.intersect(posCanDoSet);
    //如果是做过这个工序的，检查一下现在做做的是不是也是全部在库的，如果是，不可以发
    if (s->pOp->mScheduling->misHaveDonePos.contains(s->Position))
    {
        CJgOrderProcess * pOpTemp = this->preScheduling->GetProcessWorkingByPosition(s->Position);
        if (pOpTemp == nullptr)
        {
            why = "全部在库只做做过判断，做过且当前没有正在做的工序，可以发；";//147
            return true;
        }
        else
        {
            if ((this->IsAllUndoInLibAndFew(pOpTemp)) && (pOpTemp->mScheduling->mBoxesInLib.miBoxCnt > 0))
            {
                why = "全部在库只做做过判断，做过但是当前正在做的工序也是全部在库的，不可以切换；";//44
                return false;
            }
            else
            {
                why = "全部在库只做做过判断，做过且当前正在做的工序 不是全部在库或已经做完，可以发；";//3140
                return true;
            }
        }
    }
    else
    {
        if (sDoneDoing.count() == 0)
        {
            why = "全部在库只做做过判断，没有人做过这个工序，可以发；";//1904
            return true;
        }
        /*QVector< CJgOrderProcess *> vecProcess;
        if (s->pOp->pOrder)
        {
            if (s->pOp->pOrder->mOrderProcessSetGroupByPart.contains(s->pOp->mPartName))
            {
                vecProcess = s->pOp->pOrder->mOrderProcessSetGroupByPart[s->pOp->mPartName];
            }
        }
        if (0 == CPreScheduling::FindBeforeProcessOneStepCNT2(this->pSchData->hOrderProcessDependency,
            vecProcess, s->pOp))
        {
            why = "全部在库只做做过判断，没有做过这个工序但是这个工序是最前面的工序，可以发；";
            return true;
        }*/
        if (sDoneDoing.count() < (s->pOp->mScheduling->mIncDecFlag + s->pOp->mScheduling->misWorkingPos.count()))
        {
            why = "全部在库只做做过判断，没有做过这个工序但是做过本工序的人数小于需要加到的人数，可以发；";//5
            return true;
        }
        why = "全部在库只做做过判断，没有做过,有人做过，用做过的人来加人足够，不可以发；";//12461
        return false;
    }
    why = "全部在库只做做过判断，未明，可以发；";//0
    return true;
}

bool CSchProcessPosition::IsAllUndoInLibAndFew(CJgOrderProcess * pOp)
{
    if (pOp == nullptr)return false;
    if (pOp->IsMidCheck())
    {
        return true;
    }
    //if (false == IsAllUndoInLib(vPid))
    if (false == pOp->mScheduling->mbAllUnDoInLib)
    {
        return false;
    }
    if (pOp->pOrder == nullptr)
    {
        return false;
    }
    if (false == pOp->pOrder->mCurBoxSetGroupByPart.contains(pOp->mPartName))
    {
        return true;
    }
    const QVector<CJgBoxData *> & boxes = pOp->pOrder->mCurBoxSetGroupByPart[pOp->mPartName];
    int iKnowCnt = 0;
    for (CJgBoxData * box : boxes)
    {
        if (box->miPartSeqNum == pOp->miPartSeqNum)
        {
            iKnowCnt += box->miPlanCnt;
        }
    }
    int leftPiece = pOp->pOrder->miTotalPlanCnt - pOp->miFinishedCnt - iKnowCnt;
    //int paramBoxCnt = this->pSchData->hParamSet["MinInLibBoxPer"]->ValueInt();
    //int ParamSTDcnt = this->pSchData->hParamSet["MinInLibSTDPer"]->ValueInt();
    if ((pOp->mScheduling->mBoxesInLib.miBoxCnt == 0) && (leftPiece <= 0))
    {
        //没有在库的了，不用处理
        return false;
    }
    if (pOp->mScheduling->mBoxesInLib.miBoxCnt <= gRuleMinBoxInLib)
    {
        return true;
    }

    float totalInlibSecond = 0.0;
    totalInlibSecond = pOp->mfProcessStdTime;
    totalInlibSecond *= iKnowCnt;
    if (totalInlibSecond <= gRuleMinStdtimeInLib)
    {
        return true;
    }
    return false;
}

bool CSchProcessPosition::RecheckCanSend_WaitBest(SSCORE * s, QString &why)
{
    /*CJgPosition posObj;
    posObj = theApp.pRIR->pPositionManager->getPosition(s->Position);
    if (posObj.miPosNum != s->Position)*/
    int posStatus = pPositionManager->getStatus(s->Position);
    if (posStatus == -1)
    {
        why = ",判断是否等待最佳工序，无法确认工位数据，不可以发；";
        return false;
    }
    if (posStatus == FREE_P_S)
    {
        why = ",空闲状态不需要判断是否等待最佳工序，可以发；";
        return true;
    }
    qlonglong curPosProID = pPositionManager->getCurrentProcessID(s->Position);
    CJgOrderProcess * pOpDoing = CSchDataCollector::findOrderProcess(
        pSchData, curPosProID);

    /*if (pOpDoing && pSchData->getUnSendCnt(pOpDoing) == 0)
    {
        why = ",正在做的工序已经全部发出不需要判断是否等待最佳工序，可以发；";
        return true;
    }
    if (pOpDoing && (pSchData->getNextCanDoBox(pOpDoing).count() == 0))
    {
        why = ",正在做的工序上道工序没人在做或回库 不需要判断是否等待最佳工序，可以发；";
        return true;
    }*/

    if (nullptr == pOpDoing)
    {
        why = ",没有正在做的工序需要判断是否等待最佳工序，可以发；";
        return true;
    }
    if (pOpDoing->miProcessId == s->ProcessID)
    {
        why = ",等待最佳工序--相同工序可以发；";
        return true;
    }
    if (pOpDoing->mScheduling->mbAllUnDoNotReady)
    {
        why = ",正在做的工序即将没有可做筐， 不需要判断是否等待最佳工序，可以发；";
        return true;
    }
    if (false== this->ProcessPosition.hScoreByProcess.contains(s->ProcessID))
    {
        why = ",等待最佳工序--没有找到工序排名，不可以发；";
        return false;
    }
    QVector<SSCORE*> gongxuxiangliang = this->ProcessPosition.hScoreByProcess[s->ProcessID];
    int i = 0;
    bool bFind = false;
    for (i = 0; i < gongxuxiangliang.count();i++ )
    {
        if (gongxuxiangliang.at(i)->Position == s->Position)
        {
            bFind = true;
            break;
        }
    }
    if (false == bFind)
    {
        why = ",等待最佳工序--本工序不在工序排名中，不可以发；";
        return false;
    }
    int n = i + 1;
    int m = 0;
    //正在做的人数
    if (false == this->ProcessPosition.hProcessSet.contains(s->ProcessID))
    {
        why = ",等待最佳工序--本工序不在工序集中，不可以发；";
        return false;
    }
    m += this->ProcessPosition.hProcessSet[s->ProcessID]->mScheduling->misWorkingPos.count();
    //加上需要加人的数量
    if (this->ProcessPosition.hProcessSet[s->ProcessID]->mScheduling->mIncDecFlag < 1)
    {
        why = ",等待最佳工序--不需要加人，不可以发；";
        return false;
    }
    m += this->ProcessPosition.hProcessSet[s->ProcessID]->mScheduling->mIncDecFlag;
    if (n > m)
    {
        why = QString(",等待最佳工序--排名%1大于总需要人数%2，不可以发；").arg(n).arg(m);
        return false;
    }
    why = QString(",等待最佳工序--排名%1小于等于总需要人数%2，可以发；").arg(n).arg(m);
    return true;
}
